home *** CD-ROM | disk | FTP | other *** search
/ Visual Basic Graphics Programming (2nd Edition) / Visual Basic Graphics Programming 2nd Edition.iso / OldSrc / CH13 / SRC / OBJSPHR2.CLS < prev    next >
Encoding:
Text File  |  1996-04-12  |  11.6 KB  |  434 lines

  1. VERSION 1.0 CLASS
  2. BEGIN
  3.   MultiUse = -1  'True
  4. END
  5. Attribute VB_Name = "ObjSphere"
  6. Attribute VB_Creatable = False
  7. Attribute VB_Exposed = False
  8. Option Explicit
  9.  
  10. Private Radius As Single
  11. Private Center As Point3D
  12.  
  13. Private HitX As Single
  14. Private HitY As Single
  15. Private HitZ As Single
  16.  
  17. Private Kar As Single
  18. Private Kag As Single
  19. Private Kab As Single
  20.  
  21. Private Kdr As Single
  22. Private Kdg As Single
  23. Private Kdb As Single
  24.  
  25. Private SpecN As Single
  26. Private Ks As Single
  27.  
  28. Private Krr As Single
  29. Private Krg As Single
  30. Private Krb As Single
  31.  
  32. Private Nt As Single
  33. Private N1 As Single   ' Index of refraction outside the object.
  34. Private N2 As Single   ' Index of refraction inside the object.
  35. Private Ktr As Single
  36. Private Ktg As Single
  37. Private Ktb As Single
  38.  
  39. Private IsReflective As Boolean
  40. Private IsTransparent As Boolean
  41.  
  42. ' ************************************************
  43. ' Apply a transformation matrix to the sphere.
  44. ' ************************************************
  45. Public Sub Apply(M() As Single)
  46.     ' Transform the center.
  47.     m3Apply Center.coord, M, Center.trans
  48. End Sub
  49. ' ************************************************
  50. ' Return the red, green, and blue components of
  51. ' the surface at the hit position.
  52. ' ************************************************
  53. Public Sub HitColor(depth As Integer, Objects As Collection, R As Integer, G As Integer, B As Integer)
  54. Dim nx As Single
  55. Dim ny As Single
  56. Dim nz As Single
  57. Dim lx As Single
  58. Dim ly As Single
  59. Dim lz As Single
  60. Dim Vx As Single
  61. Dim Vy As Single
  62. Dim Vz As Single
  63. Dim rx As Single
  64. Dim ry As Single
  65. Dim rz As Single
  66. Dim n_len As Single
  67. Dim l_len As Single
  68. Dim v_len As Single
  69. Dim r_len As Single
  70. Dim NdotL As Single
  71. Dim RdotV As Single
  72. Dim NdotV As Single
  73. Dim r_dif As Single
  74. Dim g_dif As Single
  75. Dim b_dif As Single
  76. Dim r_amb As Single
  77. Dim g_amb As Single
  78. Dim b_amb As Single
  79. Dim spec As Single
  80. Dim r_ref As Single
  81. Dim g_ref As Single
  82. Dim b_ref As Single
  83. Dim r1 As Integer
  84. Dim g1 As Integer
  85. Dim b1 As Integer
  86. Dim mx As Single
  87. Dim my As Single
  88. Dim mz As Single
  89. Dim LdotV As Single
  90. Dim r_trd As Single
  91. Dim g_trd As Single
  92. Dim b_trd As Single
  93. Dim r_tra As Single
  94. Dim g_tra As Single
  95. Dim b_tra As Single
  96. Dim tx As Single
  97. Dim ty As Single
  98. Dim tz As Single
  99. Dim n_ratio As Single
  100. Dim cos2 As Single
  101. Dim cos1 As Single
  102. Dim cos_factor As Single
  103. Dim NdotT As Single
  104. Dim NdotT_Nt As Single
  105. Dim hit_x As Single
  106. Dim hit_y As Single
  107. Dim hit_z As Single
  108. Dim i As Integer
  109. Dim dist As Single
  110. Dim shadowed As Boolean
  111. Dim rlng As Long
  112. Dim glng As Long
  113. Dim blng As Long
  114.  
  115.     hit_x = HitX
  116.     hit_y = HitY
  117.     hit_z = HitZ
  118.  
  119.     ' *******************************
  120.     ' * Compute local contributions *
  121.     ' *******************************
  122.     
  123.     ' Find the unit vector pointing toward the light.
  124.     lx = LightSource.trans(1) - hit_x
  125.     ly = LightSource.trans(2) - hit_y
  126.     lz = LightSource.trans(3) - hit_z
  127.     l_len = Sqr(lx * lx + ly * ly + lz * lz)
  128.     lx = lx / l_len
  129.     ly = ly / l_len
  130.     lz = lz / l_len
  131.     ' We will use l_len later as the distance from
  132.     ' the light to the surface.
  133.  
  134.     ' Find the surface unit normal.
  135.     nx = hit_x - Center.trans(1)
  136.     ny = hit_y - Center.trans(2)
  137.     nz = hit_z - Center.trans(3)
  138.     n_len = Sqr(nx * nx + ny * ny + nz * nz)
  139.     nx = nx / n_len
  140.     ny = ny / n_len
  141.     nz = nz / n_len
  142.     
  143.     ' See if the light shines directly on the surface.
  144.     For i = 1 To Objects.Count
  145.         dist = Objects.Item(i).RayDistance( _
  146.             LightSource.trans(1), _
  147.             LightSource.trans(2), _
  148.             LightSource.trans(3), _
  149.             -lx, -ly, -lz)
  150.         If dist < l_len - 0.1 Then Exit For
  151.     Next i
  152.     shadowed = (i <= Objects.Count)
  153.  
  154.     ' Find vector R in the mirror direction.
  155.     NdotL = nx * lx + ny * ly + nz * lz
  156.     rx = 2 * nx * NdotL - lx
  157.     ry = 2 * ny * NdotL - ly
  158.     rz = 2 * nz * NdotL - lz
  159.     
  160.     ' Find the vector V from the surface to the
  161.     ' viewpoint.
  162.     Vx = EyeX - hit_x
  163.     Vy = EyeY - hit_y
  164.     Vz = EyeZ - hit_z
  165.     v_len = Sqr(Vx * Vx + Vy * Vy + Vz * Vz)
  166.     Vx = Vx / v_len
  167.     Vy = Vy / v_len
  168.     Vz = Vz / v_len
  169.     
  170.     ' Calculate the part due to diffuse reflection.
  171.     If shadowed Then NdotL = -1
  172.     If NdotL < 0 Then
  173.         ' The light does not hit the surface.
  174.         r_dif = 0
  175.         g_dif = 0
  176.         b_dif = 0
  177.         spec = 0
  178.     Else
  179.         r_dif = Kdr * NdotL
  180.         g_dif = Kdg * NdotL
  181.         b_dif = Kdb * NdotL
  182.         
  183.         ' Calculate the part due to specular reflection.
  184.         RdotV = rx * Vx + ry * Vy + rz * Vz
  185.         If RdotV < 0 Then
  186.             spec = 0
  187.         Else
  188.             spec = Ks * RdotV ^ SpecN
  189.         End If
  190.     End If
  191.     
  192.     ' Calculate the part due to ambient light.
  193.     r_amb = LightIar * Kar
  194.     g_amb = LightIag * Kag
  195.     b_amb = LightIab * Kab
  196.  
  197.     ' **********************************
  198.     ' * Compute reflected contribution *
  199.     ' **********************************
  200.     NdotV = nx * Vx + ny * Vy + nz * Vz
  201.     r_ref = 0
  202.     g_ref = 0
  203.     b_ref = 0
  204.     If IsReflective And depth > 1 Then
  205.         ' Find vector M in the direction of reflection.
  206.         mx = 2 * nx * NdotV - Vx
  207.         my = 2 * ny * NdotV - Vy
  208.         mz = 2 * nz * NdotV - Vz
  209.         
  210.         TraceRay depth - 1, hit_x, hit_y, hit_z, mx, my, mz, r1, g1, b1
  211.         r_ref = Krr * r1
  212.         g_ref = Krg * g1
  213.         b_ref = Krb * b1
  214.     End If
  215.     
  216.     ' **********************************
  217.     ' * Compute refracted contribution *
  218.     ' **********************************
  219.     r_trd = 0
  220.     g_trd = 0
  221.     b_trd = 0
  222.     r_tra = 0
  223.     g_tra = 0
  224.     b_tra = 0
  225.     If IsTransparent Then
  226.         ' Find the transmission vector T.
  227.         If NdotV > 0 Then
  228.             ' The ray is entering this object.
  229.             cos1 = NdotV
  230.         Else
  231.             ' The ray is exiting this object.
  232.             cos1 = -NdotV
  233.         End If
  234.         n_ratio = N1 / N2
  235.         cos2 = Sqr(1 - (1 - cos1 * cos1) * n_ratio * n_ratio)
  236.         cos_factor = cos2 - cos1 * n_ratio
  237.         tx = -Vx * n_ratio - cos_factor * nx
  238.         ty = -Vy * n_ratio - cos_factor * ny
  239.         tz = -Vz * n_ratio - cos_factor * nz
  240.         
  241.         ' If LdotV < 0, the viewpoint and light are on
  242.         ' opposite sides of the surface. In that case
  243.         ' there is direct transmitted light and no
  244.         ' specular reflection.
  245.         '
  246.         ' If LdotV > 0, the viewpoint and light are on
  247.         ' the same side of the surface. Then there
  248.         ' is specular reflection and no direct
  249.         ' transmitted light.
  250.         LdotV = lx * Vx + ly * Vy + lz * Vz
  251.         
  252.         ' Find the directly transmitted component.
  253.         If LdotV < 0 Then
  254.             NdotT = nx * tx + ny * ty + nz * tz
  255.             NdotT_Nt = NdotT ^ Nt
  256.             r_trd = Ktr * NdotT_Nt
  257.             g_trd = Ktg * NdotT_Nt
  258.             b_trd = Ktb * NdotT_Nt
  259.         End If
  260.     
  261.         ' Find the indirectly transmitted component.
  262.         If depth > 1 Then
  263.             TraceRay depth - 1, hit_x, hit_y, hit_z, tx, ty, tz, r1, g1, b1
  264.             r_tra = Ktr * r1
  265.             g_tra = Ktg * g1
  266.             b_tra = Ktb * b1
  267.         End If
  268.     End If
  269.     
  270.     ' See how intense to make the color.
  271.     ' Some of the reflections may be close to
  272.     ' the light source so these values can get big.
  273.     rlng = r_amb + _
  274.         LightIir / (l_len + LightKdist) * _
  275.             (r_dif + spec) + _
  276.         r_ref + r_tra + r_trd
  277.     glng = g_amb + _
  278.         LightIig / (l_len + LightKdist) * _
  279.             (g_dif + spec) + _
  280.         g_ref + g_tra + g_trd
  281.     blng = b_amb + _
  282.         LightIib / (l_len + LightKdist) * _
  283.             (b_dif + spec) + _
  284.         b_ref + b_tra + b_trd
  285.     If rlng > 255 Then rlng = 255
  286.     If glng > 255 Then glng = 255
  287.     If blng > 255 Then blng = 255
  288.     R = rlng
  289.     G = glng
  290.     B = blng
  291. End Sub
  292.  
  293.  
  294. ' ************************************************
  295. ' Compute the distance from point (px, py, pz)
  296. ' along vector <vx, vy, vz> to the sphere.
  297. '
  298. ' Save the point of intersection in
  299. ' (HitX, HitY, HitZ) for later use.
  300. ' ************************************************
  301. Public Function RayDistance(px As Single, py As Single, pz As Single, Vx As Single, Vy As Single, Vz As Single) As Single
  302. Dim A As Single
  303. Dim B As Single
  304. Dim C As Single
  305. Dim Cx As Single
  306. Dim Cy As Single
  307. Dim Cz As Single
  308. Dim B24AC As Single
  309. Dim t1 As Single
  310. Dim t2 As Single
  311.  
  312.     Cx = Center.trans(1)
  313.     Cy = Center.trans(2)
  314.     Cz = Center.trans(3)
  315.  
  316.     ' Get the coefficients for the quadratic.
  317.     A = Vx * Vx + Vy * Vy + Vz * Vz
  318.     B = 2 * Vx * (px - Cx) + _
  319.         2 * Vy * (py - Cy) + _
  320.         2 * Vz * (pz - Cz)
  321.     C = Cx * Cx + Cy * Cy + Cz * Cz + _
  322.         px * px + py * py + pz * pz - _
  323.         2 * (Cx * px + Cy * py + Cz * pz) - _
  324.         Radius * Radius
  325.  
  326.     ' Solve the quadratic A*t^2 + B*t + C = 0.
  327.     B24AC = B * B - 4 * A * C
  328.     If B24AC < 0 Then
  329.         RayDistance = INFINITY
  330.         Exit Function
  331.     ElseIf B24AC = 0 Then
  332.         t1 = -B / 2 / A
  333.     Else
  334.         B24AC = Sqr(B24AC)
  335.         t1 = (-B + B24AC) / 2 / A
  336.         t2 = (-B - B24AC) / 2 / A
  337.         ' Use only positive t values.
  338.         If t1 < 0.01 Then t1 = t2
  339.         If t2 < 0.01 Then t2 = t1
  340.         ' Use the smaller t value.
  341.         If t1 > t2 Then t1 = t2
  342.     End If
  343.  
  344.     ' If there is no positive t value, there's no
  345.     ' intersection in this direction.
  346.     If t1 < 0.01 Then
  347.         RayDistance = INFINITY
  348.         Exit Function
  349.     End If
  350.     
  351.     ' Compute the actual hit location.
  352.     HitX = px + t1 * Vx
  353.     HitY = py + t1 * Vy
  354.     HitZ = pz + t1 * Vz
  355.     
  356.     ' Compute the distance from (px, py, pz).
  357.     A = px - HitX
  358.     B = py - HitY
  359.     C = pz - HitZ
  360.     RayDistance = Sqr(A * A + B * B + C * C)
  361. End Function
  362.  
  363. ' ************************************************
  364. ' Set the center.
  365. ' ************************************************
  366. Public Sub Initialize(R As Single, x As Single, y As Single, z As Single)
  367.     Radius = R
  368.     Center.coord(1) = x
  369.     Center.coord(2) = y
  370.     Center.coord(3) = z
  371.     Center.coord(4) = 1
  372. End Sub
  373.  
  374.  
  375. ' ************************************************
  376. ' Set N and Ks for specular reflection.
  377. ' ************************************************
  378. Sub SetSpec(n As Single, s As Single)
  379.     SpecN = n
  380.     Ks = s
  381. End Sub
  382.  
  383. ' ************************************************
  384. ' Set constants for diffuse reflection.
  385. ' ************************************************
  386. Sub SetKd(R As Single, G As Single, B As Single)
  387.     Kdr = R
  388.     Kdg = G
  389.     Kdb = B
  390. End Sub
  391.  
  392. ' ************************************************
  393. ' Set constants for reflected light.
  394. ' ************************************************
  395. Sub SetKr(R As Single, G As Single, B As Single)
  396.     Krr = R
  397.     Krg = G
  398.     Krb = B
  399.     IsReflective = (R > 0 Or G > 0 Or B > 0)
  400. End Sub
  401.  
  402. ' ************************************************
  403. ' Set constants for transmitted light.
  404. ' ************************************************
  405. Sub SetKt(n As Single, n_1 As Single, n_2 As Single, R As Single, G As Single, B As Single)
  406.     Nt = n
  407.     N1 = n_1
  408.     N2 = n_2
  409.     Ktr = R
  410.     Ktg = G
  411.     Ktb = B
  412.     IsTransparent = (R > 0 Or G > 0 Or B > 0)
  413. End Sub
  414.  
  415. ' ************************************************
  416. ' Set constants for ambient light.
  417. ' ************************************************
  418. Sub SetKa(R As Single, G As Single, B As Single)
  419.     Kar = R
  420.     Kag = G
  421.     Kab = B
  422. End Sub
  423.  
  424.  
  425. ' ************************************************
  426. ' Initialize N1 and N2 to default values.
  427. ' ************************************************
  428. Private Sub Class_Initialize()
  429.     N1 = 1
  430.     N2 = 1
  431. End Sub
  432.  
  433.  
  434.